package person.bluext.singlegateway.frame;


import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import person.bluext.singlegateway.common.constants.ProjectConstants;
import person.bluext.singlegateway.common.utils.ProjectStringUtils;
import person.bluext.singlegateway.frame.constants.ErrorCode;
import person.bluext.singlegateway.frame.function.AbstractFuncStore;
import person.bluext.singlegateway.frame.model.ExecuteBean;
import person.bluext.singlegateway.frame.model.FuncInfo;
import person.bluext.singlegateway.frame.model.Request;
import person.bluext.singlegateway.frame.model.Response;
import person.bluext.singlegateway.frame.threadlocal.RequestParamHolder;
import person.bluext.singlegateway.frame.utils.LogUtils;
import person.bluext.singlegateway.helper.ApplicationContextHelper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/**
 * Description : Basic controller
 *
 * @author : bluext
 */
@Slf4j
public abstract class BaseController {

    @Autowired
    private ApplicationContextHelper applicationContextHelper;

    /**
     * 处理请求
     *
     * @param jsonReqStr        请求参数
     * @param abstractFuncStore 接口注册中心
     * @param request           请求对象
     * @param response          响应对象
     * @return 处理结果
     */
    protected Response processRequest(String jsonReqStr, AbstractFuncStore abstractFuncStore, HttpServletRequest request, HttpServletResponse response) {
        Long beginMillis = System.currentTimeMillis();// 接口请求开始时间

        String traceId = ProjectStringUtils.generateDateBasedUUID();
        MDC.put(ProjectConstants.TRACE_ID, traceId);// 设置追踪ID

        Response resp;

        try {
            RequestParamHolder.reset();// 重置线程中缓存数据
            log.info(LogUtils.assembleReqInfo(request, traceId, jsonReqStr));// 打印请求信息

            // 校验请求参数为空
            if (ProjectStringUtils.isBlank(jsonReqStr)) {
                log.info(">> 接口请求参数为空");
                resp = Response.fail(ErrorCode.INVALID_PARAM.getErrorCode(), ErrorCode.INVALID_PARAM.getDesc());
            } else {
                // 转换 & 保存 请求参数
                jsonReqStr = this.transformJsonReqStr(jsonReqStr, request);
                RequestParamHolder.put(ProjectConstants.REQUEST_PARAM, jsonReqStr);
                Request _request = JSON.parseObject(jsonReqStr, Request.class);

                FuncInfo funcInfo = abstractFuncStore.getFuncInfoByFuncCode(_request.getFuncCode());
                if (funcInfo != null) {
                    // 找到正确的执行对象
                    resp = this.findAndExecute(_request, funcInfo);
                } else {
                    // 没有正确的执行对象
                    log.info(">> 没有匹配到执行对象");
                    resp = Response.fail(ErrorCode.BIZ_FAIL.getErrorCode(), ErrorCode.BIZ_FAIL.getDesc());
                }
            }
        } catch (Exception ex) {
            log.error(">> 处理请求发生异常 -> Exception:", ex);
            resp = Response.fail(ErrorCode.SERVER_ERROR.getErrorCode(), ErrorCode.SERVER_ERROR.getDesc());
        }
        log.info(LogUtils.assembleRespInfo(response, traceId, resp, beginMillis));
        return resp;
    }

    // 发送json响应内容
    protected void sendJsonResponse(HttpServletResponse response, Response resp) {
        try {
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST");
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
            // response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setCharacterEncoding(ProjectConstants.UTF_8);
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().print(resp.toJsonStr());
        } catch (Exception e) {
            // do nothing
            log.error(">> 发送JSON响应发生异常", e);
        }
    }

    // 找到handler实例后执行对应方法
    private Response findAndExecute(Request request, FuncInfo funcInfo) throws ReflectiveOperationException {
        BaseHandler handler = (BaseHandler) applicationContextHelper.getBean(ProjectStringUtils.firstLtrLower(funcInfo.getFuncClass()));
        ExecuteBean executeBean = new ExecuteBean(funcInfo.getFuncName(), request.getReqParamStr(), MDC.get(ProjectConstants.TRACE_ID));
        return handler.execute(executeBean);
    }

    // 如果请求内容格式为application/x-www-form-urlencoded，则将其转换为json格式
    private String transformJsonReqStr(String jsonReqStr, HttpServletRequest request) throws UnsupportedEncodingException {
        if (StringUtils.isNotBlank(request.getContentType()) && StringUtils.containsIgnoreCase(request.getContentType(), "application/x-www-form-urlencoded")) {
            if (StringUtils.isNotBlank(jsonReqStr) && jsonReqStr.endsWith("=")) {
                jsonReqStr = jsonReqStr.substring(0, jsonReqStr.length() - 1);
            }

            StringBuilder resultBuilder = new StringBuilder("{");
            String[] tmpArr = jsonReqStr.split("&");
            for (String ele : tmpArr) {
                String[] tmpArr2 = ele.split("=");
                if (tmpArr2.length <= 1 || StringUtils.isBlank(tmpArr2[0]) || StringUtils.isBlank(tmpArr2[1])) {
                    continue;
                }
                String value = URLDecoder.decode(tmpArr2[1], ProjectConstants.UTF_8);
                resultBuilder.append("\"").append(tmpArr2[0]).append("\"").append(":\"").append(value.replace("\"", "\\\"")).append("\",");
            }

            String result = resultBuilder.toString();
            if (result.endsWith(",")) {
                result = result.substring(0, result.length() - 1);
            }

            result += "}";

            return result;
        }

        return jsonReqStr;
    }

}
